﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace Palc.XMPP
{
    public class Stream
    {
        #region Private attributes

        private bool readyForOpeningConnection = false;
        private bool connectionEstablished = false;

        private int port = 5223; //TODO make port of stream configurable

        private IPHostEntry host = null;
        private IPAddress[] hostIpList = null;
        private Socket socket = null;

        #endregion

        #region Core Stream Properties

        /// <summary>
        /// Returns the hostname this stream will try to connect to or is currently connected. Can not be modified while stream is open.
        /// </summary>
        public string Host
        {
            get
            {
                if (host == null)
                    return String.Empty;
                else
                    return this.host.HostName.ToString();
            }
            set
            {
                if (this.connectionEstablished)
                    return;

                try
                {
                    this.host = Dns.GetHostEntry(value);
                    this.hostIpList = this.host.AddressList;
                    readyForOpeningConnection = true;
                }
                catch
                {
                    //TODO message bad host to user, log this info?
                    this.host = null;
                    readyForOpeningConnection = false;
                }
            }
        }

        /// <summary>
        /// Returns true if the Open method was called successfully and a connection to the remote host was establisehd.
        /// </summary>
        public bool IsStreamOpen
        {
            get
            {
                return this.connectionEstablished;
            }
        }

        #endregion

        #region Methods for opening and closing the stream

        /// <summary>
        /// The stream will open a connection to the host.
        /// </summary>
        /// <returns>
        /// True if connection was established.
        /// False if connection failed.
        /// </returns>
        public bool Open(string hostname)
        {
            this.Host = hostname;
            if (readyForOpeningConnection)
            {
                return this.Open();
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// If the hostname has been set a conneciton to the remote host will be created.
        /// </summary>
        /// <returns>
        /// True if connection was established.
        /// False if connection failed.
        /// </returns>
        public bool Open()
        {
            IPEndPoint endpoint;
            

            if (!readyForOpeningConnection)
                return false;

            if (this.hostIpList.Length < 1)
                return false;

            this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            
            endpoint = new IPEndPoint (this.hostIpList[0], this.port);

            try
            {
                this.socket.Connect(endpoint);
            }
            catch
            {
                //TODO message connection failed to user, log this info?
                return false;
            }

            if (!socket.Connected)
                return false;

            this.connectionEstablished = true;
            return true;
        }

        /// <summary>
        /// Closes the stream immediately. No further Stanzas will be submitted!
        /// </summary>
        public void Close()
        {
            if (this.socket.Connected)
                this.socket.Close();

            this.connectionEstablished = false;
        }

        #endregion

        /// <summary>
        /// Sends a Stanza via an established connection to the remote host.
        /// </summary>
        public void Send(Stanza stanza)
        {
            throw new System.NotImplementedException();
        }
    }
}
